skip_docs

desc "Runs the unit tests and other verifications for the fastlane repo"
lane :test do |options|
  validate_repo
end

desc "Increment the version number of this gem"
lane :bump do |options|
  ensure_git_branch(branch: "master")
  ensure_git_status_clean

  github_api_token = ENV["FL_GITHUB_RELEASE_API_TOKEN"]
  UI.user_error!("Please provide a GitHub API token using `FL_GITHUB_RELEASE_API_TOKEN`") if github_api_token.to_s.length == 0

  path = "./fastlane/lib/fastlane/version.rb"

  # Verify everything is in a consistent state
  latest_version = current_version
  local_version = version_get_podspec(path: path)
  UI.user_error!("Version on RubyGems doesn't match local repo: #{latest_version} != #{local_version}") if latest_version != local_version

  changelog_text = show_changelog

  bump_type ||= 'minor' if prompt(text: "New feature, method or API?", boolean: true)
  bump_type ||= 'patch'

  slug = "fastlane/fastlane"
  new_version = version_bump_podspec(path: path, bump_type: bump_type)
  sh "git checkout -b 'version-bump-#{new_version}'"
  commit_message = "Version bump to #{new_version}"
  git_commit(path: path,
             message: commit_message)
  push_to_git_remote

  pr_body = ["Auto-generated by fastlane 🤖"]
  pr_body << "**Changes since release '#{latest_version}':**"
  pr_body << changelog_text
  pr_url = create_pull_request(
    api_token: github_api_token,
    repo: slug,
    title: commit_message,
    body: pr_body.join("\n\n")
  )

  if ENV['SLACK_URL']
    slack(
      channel: "action",
      default_payloads: [],
      message: "Version bump: #{pr_url} ✨",
      payload: {}
    )
  end

  # Revert to master branch
  sh "git checkout master"
end

desc "Does everything that's needed for a release"
desc "This includes running tests and verifying the GitHub release"
lane :release do
  update_fastlane

  # Git verification
  #
  ensure_git_status_clean
  ensure_git_branch(branch: 'master')
  git_pull

  # Verifying RubyGems version
  #
  validate_repo

  require "../fastlane/lib/fastlane/version.rb"
  version = Fastlane::VERSION
  old_version = current_version
  puts "Deploying #{version}"
  if Gem::Version.new(version) <= Gem::Version.new(old_version)
    UI.user_error!("Version number #{version} was already deployed")
  end

  # Then push to git remote
  #
  push_to_git_remote

  # Preparing GitHub Release
  #
  github_release = get_github_release(url: "fastlane/fastlane", version: version)
  if (github_release || {}).fetch('body', '').length == 0
    show_changelog(old_version: old_version)

    title = prompt(text: 'Title: ')
    description = prompt(text: "Please enter a changelog (make sure to rephrase changes to make it easy to understand, and remove non-important changes that don't affect the end-user): ",
                         multi_line_end_keyword: "END")

    github_release = set_github_release(
      repository_name: "fastlane/fastlane",
      name: [version, title].join(" "),
      tag_name: version,
      description: description,
      is_draft: false
    )

    # Actual release of the gem
    #
    sh "gem push ../pkg/fastlane-#{version}.gem"

    release_url = github_release['html_url']

    message = [title, description, release_url].join("\n\n")
    add_fastlane_git_tag(tag: "fastlane/#{version}", message: message)
  end

  # After publishing
  #
  if ENV['SLACK_URL']
    release_notes = github_release['body']
    # markup - turn github references into links
    release_notes.gsub!(/\(#([0-9]+)\)/, '(<https://github.com/fastlane/fastlane/issues/\1|#\1>)')
    slack_message = "Successfully released [fastlane #{version}](#{release_url}) :rocket:"
    slack(
      channel: "releases",
      default_payloads: [],
      message: slack_message,
      payload: {
        "New" => release_notes
      }
    )
    slack(channel: "action", default_payloads: [], message: slack_message)
  end

  clubmate
  donate_food

  puts "You can now tweet:".green
  tag_url = "https://github.com/fastlane/fastlane/releases/tag/fastlane/#{version}"
  puts "[fastlane] #{github_release['name']} #{tag_url}"

  update_docs
end

desc "Makes sure the tests on https://docs.fastlane.tools still work with the latest version"
lane :verify_docs do
  clone_docs do
    Bundler.with_clean_env do
      puts `sed -i -e "s/activate_bin_path/bin_path/g" $(which bundle)` # workaround for bundler https://github.com/bundler/bundler/issues/4602#issuecomment-233619696
      sh "bundle install"
      sh "bundle exec fastlane test skip_building:true" # skip_building since we don't have a proper python environment set up
    end
  end
end

desc "Generates the actions.md that will get used on https://docs.fastlane.tools"
desc "This will NOT also automatically submit a pull request to fastlane/docs"
desc "This SHOULD only be used for testing changes to the docs"
lane :test_generate_docs do
  ENV['USE_ENHANCE_TEST_DATA'] = "true"
  generate_markdown_docs
end

desc "Update the actions.md on https://docs.fastlane.tools"
desc "This will also automatically submit a pull request to fastlane/docs"
lane :update_docs do
  if ENV["ENHANCER_USER"].to_s.length == 0 || ENV["ENHANCER_PASSWORD"].to_s.length == 0
    UI.error("No ENHANCER_USER or ENHANCER_PASSWORD environment variables found, which are required to generate a new Actions.md")
    next
  end

  clone_docs do
    actions_md_path = generate_markdown_docs

    Bundler.with_clean_env do
      sh "bundle update"
    end

    if `git status --porcelain`.length == 0
      UI.success("No changes in the actions.md ✅")
    else
      # Create a new branch
      sh "git checkout -b 'update-actions-md-#{Time.now.to_i}'"

      Dir.chdir("fastlane") do # this is an assumption of fastlane, that we have to .. when shelling out
        # Commit the changes
        git_commit(path: [actions_md_path, "Gemfile.lock"], message: "Update actions.md for latest fastlane release 🚀")
        # Push them to the git remote
        push_to_git_remote

        # Submit the pull request
        pr_url = create_pull_request(
          api_token: ENV["FL_GITHUB_RELEASE_API_TOKEN"],
          repo: "fastlane/docs",
          title: "[Bot] Update actions.md for latest fastlane release 🚀",
          body: "Auto-generated by _fastlane_ bot 🤖"
        )
        UI.success("Successfully submitted a pull request to fastlane/docs: #{pr_url} 🚀")
      end
    end
  end
end

def generate_markdown_docs
  require 'fastlane/documentation/markdown_docs_generator'
  actions_md_path = File.expand_path("docs/actions.md")
  Fastlane::MarkdownDocsGenerator.new.generate!(target_path: actions_md_path)

  return actions_md_path
end

def clone_docs
  require 'tmpdir'
  git_url = ENV['FASTLANE_DOCS_GIT_URL'] || "https://github.com/fastlane/docs"

  Dir.mktmpdir("fl_clone") do |tmp_dir|
    Dir.chdir(tmp_dir) do
      sh "git clone #{git_url} --depth=1"
      Dir.chdir("docs") do
        yield
      end
    end
  end
end

error do |lane, exception|
  if ENV['SLACK_URL']
    slack(channel: "testing", message: exception.to_s, success: false)
  end
end

desc "Verifies all tests pass and the current state of the repo is valid"
private_lane :validate_repo do
  # Verifying that no debug code is in the code base
  #
  ensure_no_debug_code(text: "binding.pry", extension: ".rb", exclude: "playground.rb", exclude_dirs: ["\.bundle"]) # debugging code
  ensure_no_debug_code(text: "# TODO", extension: ".rb", exclude_dirs: ["\.bundle"]) # TODOs
  ensure_no_debug_code(text: "now: ", extension: ".rb", exclude_dirs: ["\.bundle"]) # rspec focus
  ensure_no_debug_code(text: "<<<<<<<", extension: ".rb", exclude_dirs: ["\.bundle"]) # Merge conflict

  rubocop

  # Verifying the --help command
  #
  # tools_to_test = Fastlane::TOOLS
  tools_to_test = [:fastlane] # until we have the binaries for all tools included here
  tools_to_test.each do |tool_name|
    next if no_binary.include?(tool_name)
    Dir.chdir("..") do
      binary_path = File.join("bin", tool_name.to_s)
      content = sh("PAGER=cat #{binary_path} --help")
      ["--version", "https://fastlane.tools", tool_name.to_s].each do |current|
        UI.user_error!("--help missing information: '#{current}'") unless content.include?(current)
      end
    end
  end

  Dir.chdir("..") do
    # Install the bundle and the actual gem
    sh "bundle check || bundle install"
    sh "rake install"

    # Run the tests
    #
    sh "bundle exec rake test_all"

    # Verify shell code style
    sh 'find -E . -regex ".*\.(sh|bash)" -not -name "Pods-*" -name ".bundle" -exec shellcheck {} +'
  end

  test_generate_docs
  ensure_code_samples

  # Verify docs are still working
  verify_docs
end

desc "Get the version number of the last release"
private_lane :current_version do
  puts "Checking the latest version on RubyGems"
  download(url: "https://rubygems.org/api/v1/gems/fastlane.json")["version"]
end

desc "All repos that don't have a binary to test"
private_lane :no_binary do
  ['fastlane_core', 'spaceship', 'credentials_manager']
end

desc "Print out the changelog since the last tagged release and open the GitHub page with the changes"
lane :show_changelog do |options|
  old_version = options[:old_version] || current_version

  changes = sh("git log --pretty='* %s' #{old_version}...HEAD --no-merges ..", log: $verbose).gsub("\n\n", "\n")
  changes.gsub!("[WIP]", "") # sometimes a [WIP] is merged

  github_diff_url = "https://github.com/fastlane/fastlane/compare/#{old_version}...master"
  sh "open #{github_diff_url}"

  puts "Changes since release #{old_version}:\n\n#{changes.cyan}"
  changes # return the text without the modified colors
end

desc "Add a git tag in the fastlane repo for this release"
private_lane :add_fastlane_git_tag do |options|
  `git tag -am #{options[:message].shellescape} #{options[:tag].shellescape}`
  push_git_tags
end

# Run the code samples, yo
private_lane :ensure_code_samples do
  UI.message "<U+1F557>  Verifying all code samples work with the latest fastlane release"
  test_sample_code(path: File.expand_path("docs/Actions.md"))
  UI.success "<U+2705>  All fastlane code samples work as expected"
end

lane :donate_food do
  if ENV["SHARETHEMEAL_USERHASH"].to_s.length > 0
    sharethemeal(
      amount: "0.5",
      currency: "USD",
      team_id: "fastlane"
    )
  end
end
